/*
 * Singularity Engine
 * Copyright (C) 2010 Vyacheslav Vorobyov, All rights reserved.
 * See LICENSE for full license information.
 */

/**
 * 
 */
package org.singularity.mapred.ui;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.geom.Rectangle2D;
import java.io.FileNotFoundException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import javax.swing.JFrame;

import org.jgraph.JGraph;
import org.jgraph.graph.DefaultGraphCell;
import org.jgraph.graph.GraphConstants;
import org.jgrapht.ListenableGraph;
import org.jgrapht.ext.JGraphModelAdapter;
import org.jgrapht.graph.ListenableDirectedGraph;
import org.singularity.io.DME;
import org.singularity.io.DMEImpl;
import org.singularity.io.Input;
import org.singularity.io.Pipe;
import org.singularity.io.PrintOutput;
import org.singularity.io.DME.Code;
import org.singularity.mapred.InputElement;
import org.singularity.mapred.MapFun;
import org.singularity.mapred.OutputElement;
import org.singularity.mapred.ReduceElement;
import org.singularity.mapred.VDME;
import org.singularity.mapred.model.DefaultCascade;
import org.singularity.mapred.util.AbstractCartesianRedFun;
import org.singularity.mapred.util.AccumulatorAdapter;
import org.singularity.mapred.util.VDMEImpl;

/**
 * @author vjache
 *
 */
public class CascadeUI extends JFrame {
	private static final long serialVersionUID = 5019449686801040707L;
	
	private static final Color     DEFAULT_BG_COLOR = Color.decode( "#FAFBFF" );
    private static final Dimension DEFAULT_SIZE = new Dimension( 530, 320 );

    // 
    @SuppressWarnings("unchecked")
	private JGraphModelAdapter m_jgAdapter;

	/**
	 * @throws Exception 
	 * 
	 */
	public CascadeUI() throws Exception {
		init();
		pack();
		setVisible(true);
	}

	@SuppressWarnings("unchecked")
	private  void init(  ) throws Exception {
		final DefaultCascade cas = createSimpleCascade(null,null);
        // create a JGraphT graph
        ListenableGraph g = new ListenableDirectedGraph( cas.getGraph() );

        // create a visualization using JGraph, via an adapter
        m_jgAdapter = new JGraphModelAdapter( g );

        JGraph jgraph = new JGraph( m_jgAdapter );

        adjustDisplaySettings( jgraph );
        getContentPane(  ).add( jgraph );
//        resize( DEFAULT_SIZE );
        
        setSize(DEFAULT_SIZE);
        
        Random rnd = new Random(System.currentTimeMillis());
        for(Object v:g.vertexSet())
        {
        	positionVertexAt( v, rnd.nextInt(DEFAULT_SIZE.width), rnd.nextInt(DEFAULT_SIZE.height));
        }

//        // add some sample data (graph manipulated via JGraphT)
//        g.addVertex( "v1" );
//        g.addVertex( "v2" );
//        g.addVertex( "v3" );
//        g.addVertex( "v4" );
//
//        g.addEdge( "v1", "v2" );
//        g.addEdge( "v2", "v3" );
//        g.addEdge( "v3", "v1" );
//        g.addEdge( "v4", "v3" );
//
//        // position vertices nicely within JGraph component
//        positionVertexAt( "v1", 130, 40 );
//        positionVertexAt( "v2", 60, 200 );
//        positionVertexAt( "v3", 310, 230 );
//        positionVertexAt( "v4", 380, 70 );

        // that's all there is to it!...
    }
	
	private void adjustDisplaySettings( JGraph jg ) {
        jg.setPreferredSize( DEFAULT_SIZE );

        Color  c        = DEFAULT_BG_COLOR;
        String colorStr = null;

//        try {
//            colorStr = Co;
//        }
//         catch( Exception e ) {}

        if( colorStr != null ) {
            c = Color.decode( colorStr );
        }

        jg.setBackground( c );
    }


    @SuppressWarnings("unchecked")
	private void positionVertexAt( Object vertex, int x, int y ) {
        DefaultGraphCell cell = m_jgAdapter.getVertexCell( vertex );
        Map              attr = cell.getAttributes(  );
        Rectangle2D        b    = GraphConstants.getBounds( attr );

        GraphConstants.setBounds( attr, new Rectangle2D.Double( x, y, b.getWidth(), b.getHeight() ) );

        Map cellAttr = new HashMap(  );
        cellAttr.put( cell, attr );
        m_jgAdapter.edit( cellAttr, null,null,null );
    }
    public static void main(String[] args) throws Exception {
		new CascadeUI();
	}
    
     
    private DefaultCascade createSimpleCascade(
			final Input<String> input1,
			final Input<String> inptu2) throws UnsupportedEncodingException, FileNotFoundException {
		DefaultCascade c = new DefaultCascade();
		
		final InputElement<String> inp1 = c.createInput(input1);
		final InputElement<String> inp2 = c.createInput(inptu2);
		
		final ReduceElement<String, String> red1 = c.createReducer(new AbstractCartesianRedFun<String, String>(){
			@Override
			protected Accumulator<String> createAccumulator(final String aKey) {
				return new AccumulatorAdapter<String>() {
					@Override
					public void onToken(Code aDmeCode, Pipe<DME<String>> aOut,
							Object[] aToken) throws Exception {
						aOut.push(new DMEImpl<String>(aDmeCode, "key= "+aKey+" "+Arrays.toString(aToken)));
					}
				};
			}
		});
		
		final MapFun<String, String, String> mapFun = new MapFun<String, String, String>() {
			@Override
			public void map(DME<String> aInput,
					Pipe<VDME<String, String>> aOutput) throws Exception {
				final String[] split = aInput.getValue().split(" ");
				final VDMEImpl<String, String> vdme = new VDMEImpl<String, String>(aInput.getCode(), split[0], split[1]);
				aOutput.push(vdme);
			}
		};
		
		c.flow(inp1, red1, mapFun);
		c.flow(inp2, red1, mapFun);
		
		//final OutputStream out = new FileOutputStream("./out.txt");
		final OutputStream out = System.out;
		final OutputElement<String> out1 = c.createOutput(new PrintOutput<String>(out));
		//final OutputElement<String> out2 = c.createOutput(new PrintOutput<String>(System.err));
		
		c.flow(red1, out1);
		//c.flow(red1, out2);
		return c;
	}
}
